#pragma once

#if defined _WIN32 || defined _WIN64
#define TOOL_API extern "C" __declspec(dllexport)
#elif defined __linux__ || defined __APPLE__
#define TOOL_API extern "C"
#endif

#if defined _WIN32 || defined _WIN64
#define CALLBACK __stdcall
#elif defined __linux__ || defined __APPLE__
#define CALLBACK
#endif

#define BOOL int

// 消息操作的类型
#define ONVIFTOOL_ADD           1       // 增加一设备
#define ONVIFTOOL_UPDATE        2       // 更新设备
#define ONVIFTOOL_DEC           3       // 设备下线
#define ONVIFTOOL_RESTART       4       // 设备重新启动
#define ONVIFTOOL_UPDATEFAIL    5       // 设备更新失败

// 常量定义
#define MAX_PASS_LEN            16      // 设备最大密码长度


// 命令码get
#define ONVIFTOOL_GET_COMMAND_STREAM_URI        1       // 获取流URI
#define ONVIFTOOL_GET_COMMAND_DEVICE_INFO       2       // 获取设备信息
#define ONVIFTOOL_GET_COMMAND_SNAPSHOT_URI      3       // 获取抓图URI
#define ONVIFTOOL_GET_COMMAND_RECORD_LIST       4       // 获取回放列表
#define ONVIFTOOL_GET_COMMAND_RECORD_URI        5       // 获取回放URI
#define ONVIFTOOL_GET_COMMAND_PRESETS           6       // 获取预置位

// 命令码set
#define ONVIFTOOL_SET_COMMAND_CHANNEL_NAME      7       // 修改通道名
#define ONVIFTOOL_SET_COMMAND_REBOOT            8       // 重启设备
#define ONVIFTOOL_SET_COMMAND_PTZ               9       // PTZ控制
#define ONVIFTOOL_SET_COMMAND_PRESET            10      // 设置预置位

// 结构体

// 网卡信息
typedef struct tagONVIFTOOL_NETWORK_INTERFACE
{
    char                szName[48];                 // 网卡名字
    char                szMAC[20];                  // 网卡物理地址
    unsigned int        dwMTU;                      // 最大传输单元
    unsigned char       byEnabled;                  // 网卡是否可用,0 不可用 1 可用

    unsigned char       byIPv4Enabled;              // IPv4地址是否可用,0 不可用 1 可用
    char                szIPv4Address[16];          // 网卡IPv4地址
    char                szIPv4SubnetMask[16];       // 网卡IPv4子网掩码
    unsigned char       byIPv4MaskLen;              // IPv4子网前缀长度
    char                szIPv4Gateway[16];          // IPv4网关
    unsigned char       byIPv4DHCPEnabled;          // IPV4 DHCP状态, 0 不启用 1 启用

    unsigned char       byIPv6Enabled;              // IPv6地址是否可用,0 不可用 1 可用
    char                szIPv6Address[46];          // 网卡IPv6地址
    unsigned char       byIPv6MaskLen;              // IPv6子网前缀长度
    char                szIPv6Gateway[46];          // IPv6网关
    unsigned char       byIPv6DHCPEnabled;          // IPV6 DHCP状态, 0 不启用 1 启用

} ONVIFTOOL_NETWORK_INTERFACE, *LPONVIFTOOL_NETWORK_INTERFACE;

// 协议信息
typedef struct tagONVIFTOOL_PROTOCOL_INFO
{
    char                szName[48];                 // 协议名
    unsigned int        dwPort;                     // 协议对应的端口号
    unsigned char       byEnabled;                  // 协议是否可用
} ONVIFTOOL_PROTOCOL_INFO, *LPONVIFTOOL_PROTOCOL_INFO;

// 设备的通道信息
typedef struct tagONVIFTOOL_VIDEO_CHANNEL_INFO
{
    unsigned char byChannelSize;            // 通道个数
    char szChannelNameArray[50][300];       // 通道名(第0项为通道1)
} ONVIFTOOL_VIDEO_CHANNEL_INFO, *LPONVIFTOOL_VIDEO_CHANNEL_INFO;

// 设备信息
typedef struct tagONVIFTOOL_DEVICE_INFO
{
    char                szSerialNO[300];                            // 设备序列号
    char                szManufacturer[300];                        // 生产商
    char                szFirmwareVersion[300];                     // 固件版本
    char                szHardwareId[300];                          // 硬件id
    char                szModel[300];                               // 型号
    char                szServiceAddr[500];                         // onvif服务地址

    // 信息类型： 1.设备上线  2.设备更新  3.设备下线  4.设备重启  5.设备更新失败
    // ONVIFTOOL_ADD        1   新设备上线，之前在列表中未出现的设备
    // ONVIFTOOL_UPDATE     2   在线的设备的网络参数或者某些状态改变
    // ONVIFTOOL_DEC        3   设备下线，设备自动发送下线消息或120秒内检测不到设备
    // ONVIFTOOL_RESTART    4   之前列表中出现过之后下线的设备再次上线
    // ONVIFTOOL_UPDATEFAIL 5   设备更新失败
    int                 iResult;
    
    unsigned int        dwNetworkInterfaceSize;                     // struNetworkInterfaceArray的大小
    ONVIFTOOL_NETWORK_INTERFACE struNetworkInterfaceArray[20];      // 网卡信息数组

    unsigned int        dwProtocolInfoSize;                         // struProtocolInfoArray的大小
    ONVIFTOOL_PROTOCOL_INFO struProtocolInfoArray[20];              // 协议信息数组

    ONVIFTOOL_VIDEO_CHANNEL_INFO struChannelInfo;                   // 通道信息

} ONVIFTOOL_DEVICE_INFO, *LPONVIFTOOL_DEVICE_INFO;

// 通过SetNetworkDefaultGateway、SetNetworkInterfaces、SetNetworkProtocols三个方法修改
// 待修改的设备网络参数
typedef struct tagONVIFTOOL_DEV_NET_PARAM
{
    char                szIPv4Address[16];                          // IPv4地址
    char                szIPv4SubNetMask[16];                       // IPv4子网掩码
    char                szIPv4Gateway[16];                          // IPv4网关
    char                szIPv6Address[128];                         // IPv6地址
    char                szIPv6Gateway[128];                         // IPv6网关
    unsigned char       byIPv6MaskLen;                              // IPv6掩码长度
    unsigned char       byDHCPEnable;                               // DHCP使能
    unsigned short      wHttpPort;                                  // HTTP端口
    unsigned char       byRes[122];
} ONVIFTOOL_DEV_NET_PARAM, *LPONVIFTOOL_DEV_NET_PARAM;

// 设备返回网络参数信息
typedef struct tagONVIFTOOL_DEV_RET_NET_PARAM
{
    unsigned char byRetryModifyTime; // 剩余可尝试修改网络参数次数
    unsigned char bySurplusLockTime; // 剩余时间，单位：分钟，用户锁定时此参数有效
    unsigned char byRes[126];
} ONVIFTOOL_DEV_RET_NET_PARAM, *LPONVIFTOOL_DEV_RET_NET_PARAM;

// 待修改的密码
typedef struct tagONVIFTOOL_RESET_PARAM
{
    unsigned char byResetType;     // 密码重置类型 0-保留,1- 通过设备序列号恢复默认密码，2-导入/导出文件重置密码，3-二维码重置， 4-GUID重置，5-安全问题重置 6-邮箱重置密码
    char szPassword[MAX_PASS_LEN]; // 新的用户密码用户密码
} ONVIFTOOL_RESET_PARAM, *LPONVIFTOOL_RESET_PARAM;

// 设备返回修改密码的信息
typedef struct tagONVIFTOOL_RET_RESET_PARAM
{
    unsigned char byRetryGUIDTime;   // 剩余可设置次数
    unsigned char bySurplusLockTime; // 剩余时间，单位：分钟，用户锁定时此参数有效
    unsigned char bRetryTimeValid;   // byRetryGUIDTime字段是否有效  0-无效,1-有效
    unsigned char bLockTimeValid;    // bySurplusLockTime字段是否有效  0-无效,1-有效
} ONVIFTOOL_RET_RESET_PARAM, *LPONVIFTOOL_RET_RESET_PARAM;

// 获取流URI输入参数
typedef struct tagONVIFTOOL_GET_STREAM_PARAM
{
    unsigned int  dwChannelNum;         // 通道号
    unsigned char byTransportType;      // 传输协议，enum{0: RtspUnicast,1: RtspMulticast,2: RTSP,3: RtspsUnicast,4: RtspsMulticast,5: RtspOverHttp}
                                        // RtspUnicast:     RTSP streaming RTP via UDP Unicast.
                                        // RtspMulticast:   RTSP streaming RTP via UDP Multicast.
                                        // RTSP:            RTSP streaming RTP over TCP.
                                        // RtspsUnicast:    Secure RTSP streaming SRTP via UDP Unicast.
                                        // RtspsMulticast:  Secure RTSP streaming SRTP via UDP Multicast.
                                        // RtspOverHttp:    Tunneling both the RTSP control channel and the RTP stream over HTTP or HTTPS.
    unsigned char byStreamType;         // 码流类型，enum{0: 主码流, 1: 子码流, 2: 第三码流}
} ONVIFTOOL_GET_STREAM_PARAM, *LPONVIFTOOL_GET_STREAM_PARAM;

// 返回URI参数
typedef struct tagONVIFTOOL_RET_GET_URI_PARAM
{
    char URI[500];      // URI
} ONVIFTOOL_RET_GET_URI_PARAM, *LPONVIFTOOL_RET_GET_URI_PARAM;

// 获取抓图URI输入参数
typedef struct tagONVIFTOOL_GET_SNAPSHOT_PARAM
{
    unsigned int   dwChannelNum;         // 通道号
} ONVIFTOOL_GET_SNAPSHOT_PARAM, *LPONVIFTOOL_GET_SNAPSHOT_PARAM;

// 获取回放列表输入参数
typedef struct tagONVIFTOOL_GET_RECORD_LIST_PARAM
{
    unsigned int    dwChannelNum;         // 通道号
    char            szBeginTime[50];      // 查询的时间范围：开始时间，格式："2022-05-11 08:11:12"
    char            szEndTime[50];        // 查询的时间范围：结束时间，格式："2022-05-11 08:11:12"
    unsigned char   byIndex;              // 查询记录的索引，0：取第0到第19条记录，1：取第20到第39条记录，以此类推，
                                          // 因为结果一次只返回20条，当超过20条时，通过这个索引，多次请求来获取全部记录
} ONVIFTOOL_GET_RECORD_LIST_PARAM, *LPONVIFTOOL_GET_RECORD_LIST_PARAM;

typedef struct tagONVIFTOOL_RET_GET_RECORD_LIST_PARAM
{
    unsigned char   byListSize;             // 回放列表大小, 最大为20个（搜索到的数目大于20时，仅显示20条并将byMore设为1）
    char            szRecordName[20][300];  // 回放的名字
    char            szStartTime[20][50];    // 回放开始时间，格式："2022-05-11 08:11:12"
    char            szStopTime[20][50];     // 回放结束时间，格式："2022-05-11 08:11:12"
    unsigned char   byMore;                 // 是否还有更多的记录，0，没有更多记录，1：还有更多记录
} ONVIFTOOL_RET_GET_RECORD_LIST_PARAM, *LPONVIFTOOL_RET_GET_RECORD_LIST_PARAM;

// 获取回放URI输入参数
typedef struct tagONVIFTOOL_GET_RECORD_URI_PARAM
{
    unsigned char byTransportType;      // 传输协议，enum{0: RtspUnicast,1: RtspMulticast,2: RTSP,3: RtspsUnicast,4: RtspsMulticast,5: RtspOverHttp}
                                        // RtspUnicast:     RTSP streaming RTP via UDP Unicast.
                                        // RtspMulticast:   RTSP streaming RTP via UDP Multicast.
                                        // RTSP:            RTSP streaming RTP over TCP.
                                        // RtspsUnicast:    Secure RTSP streaming SRTP via UDP Unicast.
                                        // RtspsMulticast:  Secure RTSP streaming SRTP via UDP Multicast.
                                        // RtspOverHttp:    Tunneling both the RTSP control channel and the RTP stream over HTTP or HTTPS.
    char szRecordName[300];             // 回放的名字
} ONVIFTOOL_GET_RECORD_URI_PARAM, *LPONVIFTOOL_GET_RECORD_URI_PARAM;

// 返回设备信息参数
typedef struct tagONVIFTOOL_RET_GET_DEVICE_INFO_PARAM
{
    char                szSerialNO[300];                            // 设备序列号
    char                szManufacturer[300];                        // 生产商
    char                szFirmwareVersion[300];                     // 固件版本
    char                szHardwareId[300];                          // 硬件id（onvif的设备名称通常使用硬件id）
    char                szModel[300];                               // 型号
    char                szMAC[20];                                  // 网卡物理地址
    int                 iOnline;                                    // 该设备是否在线, 0不在线，1在线
    int                 iChannelOnline[50];                         // 通道是否在线，0不在线，1在线
    char                szChannelNameArray[50][300];                // 通道名(该sdk最多只保存50个)
    int                 iChannelSize;                               // 通道个数
} ONVIFTOOL_RET_GET_DEVICE_INFO_PARAM, *LPONVIFTOOL_RET_GET_DEVICE_INFO_PARAM;

// 获取/设置预置位的参数
typedef struct tagONVIFTOOL_PRESET_PARAM
{
    unsigned int  dwChannelNum;             // 通道号
    unsigned char byCommand;                // 命令，enum{0: search, 1: add, 2: delete, 3:edit, 4:goto},调用get方法时选择search
    unsigned int  dwPresetIndex;            // 预置位索引，byCommand为search时无效
    char          szPresetName[300];        // 预置位名字，byCommand为add或edit时有效
    unsigned char byIndex;                  // 返回结果的索引，0：取第0到第299条记录，1：取第300到第599条记录，以此类推，
                                            // 因为结果一次只返回300条，当超过300条时，通过这个索引，多次请求来获取全部记录
} ONVIFTOOL_PRESET_PARAM, *LPONVIFTOOL_PRESET_PARAM;

// 获取/设置预置位返回的参数
typedef struct tagONVIFTOOL_RET_PRESET_PARAM
{
    unsigned int  dwListSize;                   // 预置位列表大小
    unsigned int  dwPresetIndex[300];           // 预置位索引，
    char          szPresetName[300][300];       // 预置位名字
    unsigned char byMore;                       // 是否还有更多的记录，0，没有更多记录，1：还有更多记录
} ONVIFTOOL_RET_PRESET_PARAM, *LPONVIFTOOL_RET_PRESET_PARAM;

// 设置通道名
typedef struct tagONVIFTOOL_SET_CHANNEL_PARAM
{
    unsigned int    dwChannelNum;           // 通道号
    char            szChannelName[300];     // 修改的通道名   
} ONVIFTOOL_SET_CHANNEL_PARAM, *LPONVIFTOOL_SET_CHANNEL_PARAM;

// PTZ控制
typedef struct tagONVIFTOOL_SET_PTZ_PARAM
{
    unsigned int     dwChannelNum;           // 通道号
    unsigned char    byAction;               // enum{0: startPTZ, 1: stopPTZ}
    unsigned char    byCommand;              // 命令，enum{0: left, 1: right, 2: up, 3: down, 4: left_up, 5: left_down,
                                             // 6: right_up, 7: right_down, 8: zoom_in, 9: zoom_out, 10: focus_near, 11: focus_far}
    float            speed;                  // ptz速度，范围0~1
} ONVIFTOOL_SET_PTZ_PARAM, *LPONVIFTOOL_SET_PTZ_PARAM;

typedef void(CALLBACK *PDEVICE_FIND_CALLBACK)(const ONVIFTOOL_DEVICE_INFO *lpDeviceInfo, void *pUserData);

// 获取sdk版本
TOOL_API unsigned int CALLBACK ONVIFTOOL_GetVersion();


// 设置日志 /0：debug /1: info /2: warning /3: error /4: critical
TOOL_API BOOL CALLBACK ONVIFTOOL_SetLogToFile(int nLogLevel = 0, char const *strLogDir = nullptr, int bAutoDel = 1);

// 开启发现设备的监听
TOOL_API BOOL CALLBACK ONVIFTOOL_Start(PDEVICE_FIND_CALLBACK pDeviceFindCallBack, int bInstallNPF = 0, void *pUserData = nullptr);

// 关闭监听
TOOL_API BOOL CALLBACK ONVIFTOOL_Stop();

// 登录设备,返回句柄
TOOL_API BOOL CALLBACK ONVIFTOOL_Login(const char *serviceAddr, const char *userName, const char *password,
                                       char* handleOutBuffer, unsigned int outBufferSize);

// 发送组播探测消息
TOOL_API BOOL CALLBACK ONVIFTOOL_SendInquery();

// 设置自动请求的间隔，0则不自动请求（单位s）
TOOL_API void CALLBACK ONVIFTOOL_SetAutoRequestInterval(unsigned int dwIntervalSecond);

// 修改设备网络参数
TOOL_API BOOL CALLBACK ONVIFTOOL_ModifyDeviceNetParam(const char *handle, const ONVIFTOOL_DEV_NET_PARAM *lpNetParam,
                                                      ONVIFTOOL_DEV_RET_NET_PARAM *lpRetNetParam,
                                                      unsigned int dwOutBuffSize);
// 返回失败错误码
TOOL_API unsigned int CALLBACK ONVIFTOOL_GetLastError();

// 释放资源
TOOL_API BOOL CALLBACK ONVIFTOOL_Clearup();

// 通过命令码dwCommand，获取对应命令码的设备配置
TOOL_API BOOL CALLBACK ONVIFTOOL_GetDeviceConfig(const char *handle, unsigned int dwCommand,
                                                 void *lpInBuffer, unsigned int dwInBuffSize,
                                                 void *lpOutBuffer, unsigned int dwOutBuffSize);

// 通过命令码dwCommand，设置对应命令码的设备配置
TOOL_API BOOL CALLBACK ONVIFTOOL_SetDeviceConfig(const char *handle, unsigned int dwCommand,
                                                 void *lpInBuffer, unsigned int dwInBuffSize,
                                                 void *lpOutBuffer, unsigned int dwOutBuffSize);

// 重新设置密码
TOOL_API BOOL CALLBACK ONVIFTOOL_ResetPasswd(const char *handle,
                                             const ONVIFTOOL_RESET_PARAM *pResetParam,
                                             ONVIFTOOL_RET_RESET_PARAM *pRetResetParam);